package elephant.servers.consoleserver.command.rpcserver;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

import elephant.Container;
import elephant.rpc.server.RPCServer;
import elephant.rpc.server.core.PerformMonitor;
import elephant.rpc.server.session.RPCSession;
import elephant.servers.consoleserver.command.SshdCommand;

/**
 * 
 * @author icecooly
 *
 */
public class RPCServerSshdCommand extends SshdCommand{
	//
	private RPCServer rpcServer;
	ScheduledFuture<?> futrue;
	private int totalCount;
	private int nowCount;
	public long invokeCount;
	//
	public RPCServerSshdCommand(){
		super("rpc", "rpc server");
		addOption("s",false,"show session info.",this::showSessionInfo);
		addOption("p",false,"show performance info.",this::showPerformanceInfo);
		rpcServer=Container.get().getServer(RPCServer.class);
	}
	
	//
	private void showPerformanceInfo(String args) {
		try {
			totalCount=Integer.valueOf(args);
		} catch (Exception e) {
			totalCount=0;
		}
		if(totalCount<=0){
			showPerformanceInfo(0);
			printlnHomeString();
			return;
		}
		nowCount=0;
		if(futrue!=null){
			futrue.cancel(true);
		}
		futrue=Container.get().scheduleAtFixedRate(this::showPerformanceInfo,
				0,1,TimeUnit.SECONDS);
	}
	//
	private void showPerformanceInfo(){
		nowCount++;
		if(nowCount>=totalCount){
			futrue.cancel(true);
		}
		PerformMonitor pm=rpcServer.getPerformMonitor();
		long beforeInvokeCount=invokeCount;
		invokeCount=pm.invokeCount.get();
		try {
			print("\033c");
			printlnHomeString();
			showPerformanceInfo((invokeCount-beforeInvokeCount));
			printHomeString();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	//
	private void showSessionInfo(String args){
		RPCSessionInfo[]sessions=getSessions();
		printSession(sessions);
	}
	//
	private void printSession(RPCSessionInfo[]sessions){
		if(sessions==null||sessions.length<=0){
			println("total 0 session");
			return;
		}
		Arrays.sort(sessions,(o1,o2)->{
				return o1.clientUuid.compareTo(o2.clientUuid);
		});
		println("total "+sessions.length+" session(s)");
		String format="%-5s %-8s %-20s %-8s %-20s " +
				"%-15s %-15s";
		formatPrintln(format,
				"#","ID","CLIENTID","CLUSTER","REMOTE ADDR",
				"CREATE DATE","LACC DATE",
				"TOPOCS INFO");
		SimpleDateFormat sdf=new SimpleDateFormat("MM/dd HH:mm:ss");
		for(int i=0;i<sessions.length;i++){
			formatPrintln(format,
					i+1,
					sessions[i].getId(),
					sessions[i].clientUuid,
					sessions[i].getServerCluster(),
					sessions[i].getRemoteHost()+":"+sessions[i].getRemotePort(),
					sdf.format(sessions[i].getCreateTime()),
					sdf.format(sessions[i].getLastAccessDate()),
					sessions[i].getTopics()
					);
		}
	}
	//
	private void showPerformanceInfo(long tps){
		PerformMonitor pm=rpcServer.getPerformMonitor();
		String format="%-20s: %-20s";
		formatPrintln(format, "InvokeCount",pm.invokeCount);
		formatPrintln(format, "ExceptionCount",pm.exceptionCount);
		formatPrintln(format, "LastInvokeTime(ms)",pm.lastInvokeTime);
		formatPrintln(format, "MinInvokeTime(ms)",pm.minInvokeTime);
		formatPrintln(format, "MaxInvokeTime(ms)",pm.maxInvokeTime);
		if(pm.invokeCount.get()>0){
			double avgInvokeTime=(double)(pm.totalInvokeTime.get()/pm.invokeCount.get());
			formatPrintln(format, "AvgInvokeTime(ms)",avgInvokeTime);
		}
		//
		formatPrintln(format, "TrafficIn(Byte)",pm.trafficIn.longValue());
		formatPrintln(format, "TrafficOut(Byte)",pm.trafficOut.longValue());
		formatPrintln(format, "TrafficInCount",pm.trafficInCount.longValue());
		formatPrintln(format, "TrafficOutCount",pm.trafficOutCount.longValue());
		formatPrintln(format, "Tps",tps);
		
	}
	//
	private int getSessionCount() {
		return rpcServer.getSessionManager().getSessionCount();
	}

	private RPCSessionInfo[] getSessions() {
		RPCSessionInfo infos[]=new RPCSessionInfo[getSessionCount()];
		int index=0;
		for(RPCSession s:rpcServer.getSessionManager().getSessions()){
			infos[index++]=getSessionInfo(s);
		}
		return infos;
	}
	//
	@Override
	public void onControlC() {
		totalCount=0;
	}
	//
	private RPCSessionInfo getSessionInfo(RPCSession s){
		RPCSessionInfo si=new RPCSessionInfo();
		si.id=s.id;
		si.clientUuid=s.clientUuid;
		si.serverCluster=s.serverCluster;
		si.remoteHost=s.remoteHost;
		si.remotePort=s.remotePort;
		si.createTime=new Date(s.createTime);
		si.lastAccessDate=new Date(s.lastAccessTime);
		si.topics=s.topics;
		return si;
	}
}
